//
//  AISBLEDeviceManager.m
//  ParkingCloud
//
//  Created by Ares on 16/5/9.
//  Copyright © 2016年 NJSubier. All rights reserved.
//

#import "AISBLEDeviceManager.h"
#import "AISBLEDevice.h"

@interface AISBLEDeviceManager() <CBCentralManagerDelegate> {
    CBCentralManager *mCentralManager;
    NSArray<CBUUID *> *mTargetServices;
}

@end


static AISBLEDeviceManager *gAISBLEDeviceManagerInstance = nil;

@implementation AISBLEDeviceManager

+ (AISBLEDeviceManager *)sharedInstance {
    if (nil == gAISBLEDeviceManagerInstance) {
        gAISBLEDeviceManagerInstance = [[AISBLEDeviceManager alloc] init];
    }
    return gAISBLEDeviceManagerInstance;
}

- (id)init {
    self = [super init];
    if (self) {
        mCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        
        _foundDevices = [[NSMutableArray alloc] init];
        _connectedDevices = [[NSMutableArray alloc] init];
    }
    return self;
}

#pragma mark - Property


#pragma mark - API for manage

- (void)scanDevicesWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs {
    NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
    @synchronized (mTargetServices) {
        mTargetServices = serviceUUIDs;
    }
    [mCentralManager scanForPeripheralsWithServices:serviceUUIDs options:options];
}

- (void)stopScanning {
    [mCentralManager stopScan];
}

- (void)connectDevice:(AISBLEDevice *)device {
    if (CBPeripheralStateConnected != [device.peripheral state]) {
        [mCentralManager connectPeripheral:device.peripheral options:nil];
    }
}

- (void) disconnectDevice:(AISBLEDevice *)device {
    [mCentralManager cancelPeripheralConnection:device.peripheral];
}

#pragma mark CBCentralManagerDelegate

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
    AISBLEDevice *device = nil;
    
    // 查找是否已记录该设备
    device = [self findDeviceWithPeripheral:peripheral inDeviceList:self.foundDevices];
    
    @synchronized (self.foundDevices) {
        if (nil == device) { // 没有记录则创建并记录到数组
            if ([self.deviceFactory respondsToSelector:@selector(createDevice)] && [self isTargetPeripheral:peripheral]) {
                device = [self.deviceFactory createDevice];
            } else {
                device = [[AISBLEDevice alloc] init];
            }
            device.peripheral = peripheral;
            [self.foundDevices addObject:device];
        }
        device.RSSI = RSSI;
        // 根据信号强弱排序
        [self.foundDevices sortUsingComparator:^NSComparisonResult(AISBLEDevice *obj1, AISBLEDevice *obj2) {
            return [obj2.RSSI compare:obj1.RSSI];
        }];
    }
    
    if ([self.delegate respondsToSelector:@selector(bleDeviceManagerDidRefresh)])
    {
        [self.delegate bleDeviceManagerDidRefresh];
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    AISBLEDevice *device = [self findDeviceWithPeripheral:peripheral inDeviceList:self.foundDevices];
    if (nil == device) {
        return;
    }
    
    [device.peripheral discoverServices:[device interestedServiceUUIDs]];
    
    if (nil == [self findDeviceWithPeripheral:peripheral inDeviceList:self.connectedDevices]) {
        @synchronized (self.connectedDevices) {
            [self.connectedDevices addObject:device];
        }
    }
    
    if ([self.delegate respondsToSelector:@selector(bleDeviceDidStatusChanged:)]) {
        [self.delegate bleDeviceDidStatusChanged:device];
    }
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"ConnectPeripheral Fail. Error:\n%@", error.description);
    AISBLEDevice *device = [self findDeviceWithPeripheral:peripheral inDeviceList:self.foundDevices];
    if (nil != device) {
        [device deviceConnectedFailedWithError:error];
    }
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    if (error != nil) {
        NSLog(@"DisconnectPeripheral Error:\n%@", error.description);
    }
    
    AISBLEDevice *device = [self findDeviceWithPeripheral:peripheral inDeviceList:self.foundDevices];
    if (nil == device) {
        return;
    }
    [device deviceDisconnectedWithError:error];
    
    if (nil != [self findDeviceWithPeripheral:peripheral inDeviceList:self.connectedDevices]) {
        @synchronized (self.connectedDevices) {
            [self.connectedDevices removeObject:device];
        }
    }
    
    if ([self.delegate respondsToSelector:@selector(bleDeviceDidStatusChanged:)]) {
        [self.delegate bleDeviceDidStatusChanged:device];
    }
}

#pragma mark Help functions

- (BOOL)isTargetPeripheral:(CBPeripheral *)peripheral {
    return [mTargetServices count] > 0;
}

- (AISBLEDevice *)findDeviceWithPeripheral:(CBPeripheral *)peripheral inDeviceList:(NSArray<AISBLEDevice *> *)deviceList {
    __block AISBLEDevice *retDevice = nil;
    @synchronized (deviceList) {
        [deviceList enumerateObjectsUsingBlock:^(AISBLEDevice * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj.peripheral.identifier isEqual:peripheral.identifier]) {
                retDevice = obj;
                *stop = YES;
            }
        }];
    }
    return retDevice;
}



@end
